#!/usr/bin/env bash

{

volta_unpack_volta() {
  base64 --decode <<'END_BINARY_PAYLOAD'
<PLACEHOLDER_VOLTA_PAYLOAD>
END_BINARY_PAYLOAD
}

volta_unpack_shim() {
  base64 --decode <<'END_BINARY_PAYLOAD'
<PLACEHOLDER_SHIM_PAYLOAD>
END_BINARY_PAYLOAD
}

volta_unpack_bash_launcher() {
  cat <<'END_TEXT_PAYLOAD'
<PLACEHOLDER_BASH_LAUNCHER_PAYLOAD>
END_TEXT_PAYLOAD
}

volta_unpack_fish_launcher() {
  cat <<'END_TEXT_PAYLOAD'
<PLACEHOLDER_FISH_LAUNCHER_PAYLOAD>
END_TEXT_PAYLOAD
}

volta_install_dir() {
  printf %s "${VOLTA_HOME:-"$HOME/.volta"}"
}

volta_create_tree() {
  local INSTALL_DIR

  INSTALL_DIR="$(volta_install_dir)"

  mkdir -p "${INSTALL_DIR}"

  # ~/
  #     .volta/
  #         cache/
  #             node/
  #         tools/
  #             inventory/
  #                 node/
  #                 packages/
  #                 yarn/
  #             image/
  #                 node/
  #                 yarn/
  #             user/
  #         bin/
  #         tmp/

  mkdir -p "${INSTALL_DIR}"/cache/node
  mkdir -p "${INSTALL_DIR}"/tools/inventory/node
  mkdir -p "${INSTALL_DIR}"/tools/inventory/packages
  mkdir -p "${INSTALL_DIR}"/tools/inventory/yarn
  mkdir -p "${INSTALL_DIR}"/tools/image/node
  mkdir -p "${INSTALL_DIR}"/tools/image/yarn
  mkdir -p "${INSTALL_DIR}"/tools/user
  mkdir -p "${INSTALL_DIR}"/bin
  mkdir -p "${INSTALL_DIR}"/tmp
}

volta_create_binaries() {
  local INSTALL_DIR

  INSTALL_DIR="$(volta_install_dir)"

  volta_unpack_volta        > "${INSTALL_DIR}"/volta
  volta_unpack_shim          > "${INSTALL_DIR}"/shim
  volta_unpack_bash_launcher > "${INSTALL_DIR}"/load.sh
  volta_unpack_fish_launcher > "${INSTALL_DIR}"/load.fish

  # Remove any existing binaries for tools so that the symlinks can be installed
  # using -f so there is no error if the files don't exist
  rm -f "${INSTALL_DIR}"/bin/node
  rm -f "${INSTALL_DIR}"/bin/npm
  rm -f "${INSTALL_DIR}"/bin/npx
  rm -f "${INSTALL_DIR}"/bin/yarn

  for FILE_NAME in "${INSTALL_DIR}"/bin/*; do
    if [ -e "${FILE_NAME}" ] && ! [ -d "${FILE_NAME}" ]; then
      rm -f "${FILE_NAME}"
      ln -s "${INSTALL_DIR}"/shim "${FILE_NAME}"
    fi
  done

  ln -s "${INSTALL_DIR}"/shim "${INSTALL_DIR}"/bin/node
  ln -s "${INSTALL_DIR}"/shim "${INSTALL_DIR}"/bin/npm
  ln -s "${INSTALL_DIR}"/shim "${INSTALL_DIR}"/bin/npx
  ln -s "${INSTALL_DIR}"/shim "${INSTALL_DIR}"/bin/yarn

  chmod 755 "${INSTALL_DIR}/"/volta "${INSTALL_DIR}/bin"/* "${INSTALL_DIR}"/shim
}

volta_try_profile() {
  if [ -z "${1-}" ] || [ ! -f "${1}" ]; then
    return 1
  fi
  echo "${1}"
}

# If file exists, echo it
echo_fexists() {
  [ -f "$1" ] && echo "$1"
}

volta_detect_profile() {
  if [ -n "${PROFILE}" ] && [ -f "${PROFILE}" ]; then
    echo "${PROFILE}"
    return
  fi

  # try to detect the current shell
  case "$(basename "/$SHELL")" in
    bash)
      # Shells on macOS default to opening with a login shell, while Linuxes
      # default to a *non*-login shell, so if this is macOS we look for
      # `.bash_profile` first; if it's Linux, we look for `.bashrc` first. The
      # `*` fallthrough covers more than just Linux: it's everything that is not
      # macOS (Darwin). It can be made narrower later if need be.
      case $(uname) in
        Darwin)
          echo_fexists "$HOME/.bash_profile" || echo_fexists "$HOME/.bashrc"
          ;;
        *)
          echo_fexists "$HOME/.bashrc" || echo_fexists "$HOME/.bash_profile"
          ;;
      esac
      ;;
    zsh)
      echo "$HOME/.zshrc"
      ;;
    fish)
      echo "$HOME/.config/fish/config.fish"
      ;;
    *)
      # Fall back to checking for profile file existence. Once again, the order
      # differs between macOS and everything else.
      local profiles
      case $(uname) in
        Darwin)
          profiles=( .profile .bash_profile .bashrc .zshrc .config/fish/config.fish )
          ;;
        *)
          profiles=( .profile .bashrc .bash_profile .zshrc .config/fish/config.fish )
          ;;
      esac

      for profile in "${profiles[@]}"; do
        echo_fexists "$HOME/$profile" && break
      done
      ;;
  esac
}

volta_build_path_str() {
  local PROFILE
  PROFILE="$1"
  local PROFILE_INSTALL_DIR
  PROFILE_INSTALL_DIR="$2"

  local PATH_STR
  if [[ $PROFILE =~ \.fish$ ]]; then
    PATH_STR="\\nset -gx VOLTA_HOME \"${PROFILE_INSTALL_DIR}\"\\ntest -s \"\$VOLTA_HOME/load.fish\"; and source \"\$VOLTA_HOME/load.fish\"\\n\\nstring match -r \".volta\" \"\$PATH\" > /dev/null; or set -gx PATH \"\$VOLTA_HOME/bin\" \$PATH"
  else
    PATH_STR="\\nexport VOLTA_HOME=\"${PROFILE_INSTALL_DIR}\"\\n[ -s \"\$VOLTA_HOME/load.sh\" ] && \\. \"\$VOLTA_HOME/load.sh\"\\n\\nexport PATH=\"\${VOLTA_HOME}/bin:\$PATH\""
  fi

  echo "$PATH_STR"
}

volta_eprintf() {
  command printf "$1\n" 1>&2
}

volta_info() {
  local ACTION
  local DETAILS
  ACTION="$1"
  DETAILS="$2"
  command printf '\033[1;32m%12s\033[0m %s\n' "${ACTION}" "${DETAILS}" 1>&2
}

volta_error() {
  command printf '\033[1;31mError\033[0m: ' 1>&2
  volta_eprintf "$1"
  volta_eprintf ''
}

volta_warning() {
  command printf '\033[1;33mWarning\033[0m: ' 1>&2
  volta_eprintf "$1"
}

volta_install() {
  if [ -n "${VOLTA_HOME-}" ] && [ -e "${VOLTA_HOME}" ] && ! [ -d "${VOLTA_HOME}" ]; then
    volta_error "\$VOLTA_HOME is set but is not a directory (${VOLTA_HOME})."
    volta_eprintf "Please check your profile scripts and environment."
    exit 1
  fi

  volta_info 'Creating' "Volta directory tree ($(volta_install_dir))"
  volta_create_tree

  volta_info 'Unpacking' "\`volta\` executable and shims"
  volta_create_binaries

  local VOLTA_PROFILE
  VOLTA_PROFILE="$(volta_detect_profile)"
  volta_info 'Editing' "user profile ($VOLTA_PROFILE)"

  local PROFILE_INSTALL_DIR
  PROFILE_INSTALL_DIR=$(volta_install_dir | sed "s:^$HOME:\$HOME:")
  local PATH_STR
  PATH_STR="$(volta_build_path_str "$VOLTA_PROFILE" "$PROFILE_INSTALL_DIR")"

  if [ -z "${VOLTA_PROFILE-}" ] ; then
    local TRIED_PROFILE
    if [ -n "${PROFILE}" ]; then
      TRIED_PROFILE="${VOLTA_PROFILE} (as defined in \$PROFILE), "
    fi
    volta_error "No user profile found."
    volta_eprintf "Tried ${TRIED_PROFILE-}~/.bashrc, ~/.bash_profile, ~/.zshrc, ~/.profile, and ~.config/fish/config.fish."
    volta_eprintf ''
    volta_eprintf "You can either create one of these and try again or add this to the appropriate file:"
    volta_eprintf "${PATH_STR}"
    exit 1
  else
    if ! command grep -qc 'VOLTA_HOME' "$VOLTA_PROFILE"; then
      command printf "${PATH_STR}" >> "$VOLTA_PROFILE"
    else
      volta_eprintf ''
      volta_warning "Your profile (${VOLTA_PROFILE}) already mentions"
      volta_eprintf "         Volta and has not been changed."
      volta_eprintf ''
    fi
  fi

  if command grep -qc 'NOTION_HOME' "$VOLTA_PROFILE"; then
      volta_eprintf ''
      volta_warning "Your profile (${VOLTA_PROFILE}) mentions Notion."
      volta_eprintf "         You probably want to remove that."
      volta_eprintf ''
  fi

  volta_info "Finished" 'installation. Open a new terminal to start using Volta!'
  exit 0
}

volta_install

}
